Skip to main content

04 - 卸载到外部

前置03 篇。压缩和裁剪都是有损的;本篇是第三种选择 —— 不砍,挪出去。

本篇回答:把内容放到上下文之外的三条路线各自怎么工作,以及它们分别把问题推到了哪里 —— 卸载不消灭成本,只是换一种形式付。

本篇会用到的词

意思
卸载(offload)内容存在上下文之外,上下文里只留一个能取回它的指针
结构化笔记Agent 自己在外部维护的进度、决策、待办文件。它写,它自己读
子 Agent独立开一个上下文窗口去做某个子任务,只把结论返回给主 Agent
即时检索不预先把内容塞进上下文,等真正需要时再去取。区别于"启动时全部加载"
指针文件路径、记录 ID、URL 这类几十 token 的引用

一、共同结构:上下文里只留指针

三条路线的形式不同,骨架是一样的:

代价从"token 占用"换成了"模型轮次"—— 换了一种货币,不是免费上下文里(每轮都付)指针:report_2026Q2.md(12 行)约 40 token这一步真正要用的那一小段约 800 token,用完可被裁掉按需取上下文外(存着不花 token)完整内容文件系统 / 子 Agent 的独立窗口 / 外部存储约 120,000 token,一次都不进主上下文取回那一步是一次完整的模型往返(几百毫秒到秒级)。卸载得越彻底,任务需要的轮次越多。
指针的质量决定这条路线成不成立。report.md 这样的名字模型没法判断该不该读;report_2026Q2_财务_含分季度明细.md 才能让它在不打开的情况下做决策。这一点和记忆专题 05 篇里"文件式记忆靠模型看文件名猜"是同一个约束。

二、路线 A:结构化笔记

Agent 在外部维护一组自己写、自己读的文件:进度、已做的决策、待办、踩过的坑。

<!-- progress.md —— 每个会话开头读、结尾写 -->
# 当前任务:把订单服务从 REST 迁到 gRPC

## 已完成(端到端验证过才写进这里)
- [x] proto 定义 —— 见 `api/order.proto`
- [x] 服务端实现 —— 单测通过,集成测试通过

## 进行中
- [ ] 客户端迁移 —— 已改完 3 个调用方,还剩 `billing``notify`

## 已确定的约束(不要重新讨论)
- 保留 REST 端点到 2026-12-31,两套并存
- 不引入新的序列化库,用现有的 protobuf 版本

## 踩过的坑
- `billing` 的超时是在网关侧配的,改客户端没用

三个设计要点:

  • "已完成"的判据是端到端验证通过,不是代码写完。否则进度文件会越来越不可信,而它一旦不可信,整条路线就废了
  • "已确定的约束"这一节比进度更重要。它防的是压缩之后模型重新讨论已经定过的事
  • 一次只推进一个条目。同时开三件事,写回时容易把状态写乱

这条路线的实现形态在记忆专题 05 篇里讲透了(memory 工具的六个命令、路径穿越防护、Letta 的 git 版本化目录)。区别只在目的:那边关注跨会话保管,这边关注给当前上下文腾地方。

三、路线 B:子 Agent 隔离上下文

主 Agent 把一个需要大量阅读的子任务交给子 Agent,子 Agent 用自己独立的上下文窗口去做,只把结论返回来。Anthropic 给的返回量级是 1,000 到 2,000 token

同一个调研任务:读三批资料,产出一份综述单 Agent:全部读进同一个窗口资料 A 110K资料 B 130K资料 C 100K主上下文累计 340K,且腐烂已经很明显写综述时,资料 A 已经在很靠中间的位置(02 篇位置效应)子 Agent:各读各的,只回结论子 A 窗口110K → 1.5K子 B 窗口130K → 1.5K子 C 窗口100K → 1.5K主上下文只有 4.5K 摘要 + 原有的 25K总 token 一点没少 —— 340K 照读,只是分散在四个窗口里
这张图最容易被误读成"子 Agent 省钱"。它不省钱,token 总量几乎一样,还多了三次启动开销。它换到的是主 Agent 的上下文质量 —— 主 Agent 在写综述时面对的是 30K 的干净上下文,而不是 340K 的混杂上下文。

代价要说清楚

代价具体
信息压缩比极高110K 压到 1.5K,压缩比约 70:1。主 Agent 拿不到细节,也没法追问原文
不可回溯子 Agent 的上下文用完即弃。主 Agent 后来发现摘要里某句话可疑,没法回去看依据
总 token 没降三份资料照样被完整读了一遍,只是读在别处
延迟可能更高能并行时更快,不能并行时是串行叠加
调试变难出问题时要看四条 trace 而不是一条

适用判据:子任务是"读大量内容、产出一个结论"这种形状,且结论本身足以支撑后续决策。如果主 Agent 后面还需要回到细节,这条路线就不合适 —— 改用路线 A(子 Agent 把细节写成文件,主 Agent 拿到路径)。

四、路线 C:即时检索

不预先加载,等需要时再取。这条路线在两个地方都在用:

  • 文件系统:上下文里放目录列表,模型自己决定读哪个文件
  • 工具定义:上下文里不放全部工具定义,模型搜索到再加载 —— 这就是05 篇的工具搜索

关键设计是元数据要足够模型做判断

# ❌ 只给路径,模型只能靠猜或者全读一遍
context += "\n".join(["docs/a.md", "docs/b.md", "docs/c.md"])

# ✅ 给足够判断的元信息,让模型不打开就能筛掉大部分
# 多花的这几十 token,换回的是少读两个文件的几千 token
context += """
docs/api-v2-迁移指南.md (4.2K, 2026-07 更新) —— 从 v1 迁到 v2 的步骤与断点
docs/api-v1-历史设计.md (18K, 2024-03 更新) —— v1 的设计背景,已归档
docs/部署手册.md (6.1K, 2026-08 更新) —— 环境变量、灰度、回滚
"""

这里有一个和"卸载"方向相反的取舍:元数据本身也占上下文。三个文件的元信息才几十 token,三千个文件的目录列表就是几万 token —— 那时候元数据本身就成了要卸载的对象,得再套一层(先列目录、再列子目录)。

五、三条路线怎么选

维度A · 结构化笔记B · 子 AgentC · 即时检索
卸载的是什么进度与决策一整段阅读与推理过程尚未用到的资料与工具
主上下文里留什么文件路径1,000–2,000 token 的摘要带元信息的索引
细节还能不能取回能,重新读文件不能,子上下文已弃能,重新检索
额外的模型轮次每次读写各一次每个子任务一次完整会话每次取回一次
总 token略增(读写的往返)基本不变明显下降(大部分资料从没进过上下文)
主要适合长周期、可中断的任务读得多、结论短的子任务资料库大、单次只用一小部分

三条可以叠加,而且在成熟的 Agent 里通常是叠加的:子 Agent 把调研结论写成文件(B + A),主 Agent 通过带元信息的索引按需读(C)。

六、卸载把问题推到了哪里

这一节是这条路线最容易被跳过的部分。

四条都不是理论风险,是把内容挪出去之后必然要处理的① 模型可能不去取指针在上下文里但模型选择不读没有机制能强制它读提示词只能提高概率② 外部状态会漂上下文里的摘要说 A文件已经被改成 B谁是权威要事先定死否则模型按哪个来都对③ 轮次变多每次取回一次往返几百毫秒到秒级卸载越彻底轮次越多对首字延迟直接可见④ 排查跨条主 Agent 一条 trace每个子 Agent 各一条要能按父子关系串起来见可观测性 01 篇①最没有好办法。真正关键的信息(安全约束、硬性要求)不要卸载 —— 它们应该常驻上下文,代价是几百 token,值得。
第②条在结构化笔记路线上尤其常见:Agent 在上下文里记着"配置是 A",同时文件里已经写成 B。解法是定死单一权威源 —— 要么每轮重读文件,要么明确规定上下文里的副本只是缓存、以文件为准,并在提示词里写清楚。

七、小结

  • 卸载不消灭成本,把"token 占用"换成了"模型轮次",是换货币不是免费
  • 指针的质量决定成败:文件名必须让模型在不打开的情况下就能判断该不该读
  • 结构化笔记的两个纪律:完成的判据是端到端验证通过,"已确定的约束"那一节比进度更重要
  • 子 Agent 不省 token,省的是主 Agent 的上下文质量;代价是 70:1 的压缩比和不可回溯
  • 即时检索的元数据本身也占上下文,资料量大到一定程度要再套一层索引
  • 卸载的四类新问题里,"模型可能不去取"没有好办法 —— 关键信息不要卸载

下一篇:05 - 工具与检索结果的占用,第三类手段 —— 从源头上就别让它进来。

← 回到 专题索引